﻿using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core;
using Aliyun.Acs.Push.Model.V20160801;
using LJ.Abstractions.Exceptions;
using LJ.Abstractions.Extensions;
using LJ.FaultHandler.Abstractions;
using LJ.MobilePush.Abstractions;
using Microsoft.Extensions.Logging;

namespace LJ.MobilePush.Aliyun.Internal;

public class AliyunMobilePush(IServiceProvider serviceProvider, IFaultHandlerFactory faultHandlerFactory) : IMobilePush
{
    private long appKey = 0;

    private readonly IFaultHandlerFactory _faultHandlerFactory = faultHandlerFactory;
    private readonly MobilePushConfig _mobilePushConfig = serviceProvider.GetConfig<MobilePushConfig>();
    private readonly ILogger _logger = serviceProvider.GetLogger<AliyunMobilePush>();

    public void SetAppKey(string key)
    {
        var config = _mobilePushConfig.Infos.Where(a => a.Key == key).FirstOrDefault() ?? throw new AppException($"{GetType().FullName} AliyunMobilePush is not {key}");
        appKey = config.AppId;
    }
    private DefaultAcsClient GetDefaultAcsClient()
    {
        var clientProfile = DefaultProfile.GetProfile(_mobilePushConfig.RegionId, _mobilePushConfig.AccessKeyId, _mobilePushConfig.Secret);
        var client = new DefaultAcsClient(clientProfile);
        return client;
    }

    public async Task BindTagByDeviceAsync(List<string> tagNames, List<string> targets, CancellationToken cancellationToken = default)
    {

        try
        {
            var faultHandler = _faultHandlerFactory.Create();
            await faultHandler.ExecuteAsync(a =>
            {
                var clientKey = string.Join(",", targets);
                var tagName = string.Join(",", tagNames);
                var client = GetDefaultAcsClient();
                var request = new BindTagRequest
                {
                    AppKey = appKey,
                    KeyType = "DEVICE",//设备：DEVICE 账号：ACCOUNT 别名：ALIAS
                    ClientKey = clientKey,//一次最多可以绑定1000个Key到10个tag上
                    TagName = tagName//一次最多可以绑定1000个Key到10个tag上
                };
                client.GetAcsResponse(request);

                return Task.CompletedTask;

            }, cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError("MobilePush Aliyun  [{messagename}] {Exception}.", nameof(BindTagByDeviceAsync), e);
            throw;
        }

    }

    public async Task UnbindTagByDeviceAsync(string tagName, List<string> targets, CancellationToken cancellationToken = default)
    {

        try
        {
            var faultHandler = _faultHandlerFactory.Create();

            await faultHandler.ExecuteAsync(a =>
            {

                var clientKey = string.Join(",", targets);
                var client = GetDefaultAcsClient();
                var request = new UnbindTagRequest
                {
                    AppKey = appKey,
                    KeyType = "DEVICE",//设备：DEVICE 账号：ACCOUNT 别名：ALIAS
                    ClientKey = clientKey,//一次最多可以绑定1000个Key到10个tag上
                    TagName = tagName//一次最多可以绑定1000个Key到10个tag上
                };
                client.GetAcsResponse(request);
                return Task.CompletedTask;

            }, cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError("MobilePush Aliyun  [{messagename}] {Exception}.", nameof(UnbindTagByDeviceAsync), e);
            throw;
        }

    }

    public async Task<List<string>> GetTagListAsync(CancellationToken cancellationToken = default)
    {
        try
        {
            var faultHandler = _faultHandlerFactory.Create();

            return await faultHandler.ExecuteAsync(a =>
            {

                var client = GetDefaultAcsClient();
                var request = new ListTagsRequest
                {
                    AppKey = appKey,
                };

                var response = client.GetAcsResponse(request);
                return Task.FromResult(response.TagInfos.Select(a => a.TagName).ToList());
            }, cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError("MobilePush Aliyun  [{messagename}] {Exception}.", nameof(GetTagListAsync), e);
            throw;
        }

    }

    public async Task PushByDeviceAsync(List<string> targets, PushData pushData, CancellationToken cancellationToken = default)
    {
        try
        {
            var faultHandler = _faultHandlerFactory.Create();

            await faultHandler.ExecuteAsync(async a =>
            {

                var clientKey = string.Join(",", targets);
                await PushAsync(TargetType.Device, clientKey, pushData);

            }, cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError("MobilePush Aliyun  [{messagename}] {Exception}.", nameof(PushByTagAsync), e);
            throw;
        }
    }

    public async Task PushByTagAsync(string tag, PushData pushData, CancellationToken cancellationToken = default)
    {
        try
        {
            var faultHandler = _faultHandlerFactory.Create();

            await faultHandler.ExecuteAsync(async a =>
            {

                await PushAsync(TargetType.Tag, tag, pushData);

            }, cancellationToken);
        }
        catch (Exception e)
        {
            _logger.LogError("MobilePush Aliyun  [{messagename}] {Exception}.", nameof(PushByTagAsync), e);
            throw;
        }
    }

    #region private
    private Task PushAsync(TargetType targetType, string targetValue, PushData pushData)
    {
        var client = GetDefaultAcsClient();
        var env = _mobilePushConfig.Env switch
        {
            EnvType.Dev => "DEV",
            EnvType.Product => "PRODUCT",
            _ => throw new AppException($"{GetType().FullName} {nameof(_mobilePushConfig.Env)}  is null"),
        };

        var target = targetType switch
        {
            TargetType.Device => "DEVICE",
            TargetType.Tag => "TAG",
            _ => throw new AppException($"{GetType().FullName} {nameof(targetType)}  is null"),
        };


        var request = new PushRequest
        {
            // 推送目标
            AppKey = appKey,
            //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
            Target = target,
            //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
            TargetValue = targetValue,
            //消息类型 MESSAGE NOTICE
            PushType = "NOTICE",
            //设备类型 ANDROID iOS ALL.
            DeviceType = "ALL",
            // 消息的标题
            Title = pushData.Title,
            // 消息的内容
            Body = pushData.Body,

            // 推送配置: iOS
            // iOS应用图标右上角角标
            IOSBadge = 50,
            //开启静默通知
            IOSSilentNotification = false,
            // iOS通知声音
            IOSMusic = "default",
            //iOS10通知副标题的内容
            //request.IOSSubtitle = "iOS10 subtitle";
            ////指定iOS10通知Category
            //request.IOSNotificationCategory = "iOS10 Notification Category";
            //是否允许扩展iOS通知内容
            IOSMutableContent = true,
            //iOS的通知是通过APNs中心来发送的，需要填写对应的环境信息。"DEV" : 表示开发环境 "PRODUCT" : 表示生产环境
            IOSApnsEnv = env,
            //消息推送时设备不在线（既与移动推送的服务端的长连接通道不通），则这条推送会做为通知，通过苹果的APNs通道送达一次。注意：离线消息转通知仅适用于生产环境
            IOSRemind = true,
            //iOS消息转通知时使用的iOS通知内容，仅当iOSApnsEnv=PRODUCT && iOSRemind为true时有效
            IOSRemindBody = "iOSRemindBody",
            //自定义的kv结构,开发者扩展用 针对iOS设备
            //request.IOSExtParameters = "{\"key1\":\"value1\"}";

            // 推送配置: Android
            // 通知的提醒方式 "VIBRATE" : 震动 "SOUND" : 声音 "BOTH" : 声音和震动 NONE : 静音
            AndroidNotifyType = "BOTH",
            //通知栏自定义样式0-100
            AndroidNotificationBarType = 3,
            //通知栏显示优先级
            AndroidNotificationBarPriority = 0,
            //点击通知后动作 "APPLICATION" : 打开应用 "ACTIVITY" : 打开AndroidActivity "URL" : 打开URL "NONE" : 无跳转
            AndroidOpenType = "NONE",
            //Android收到推送后打开对应的url,仅当AndroidOpenType="URL"有效
            //request.AndroidOpenUrl = "http://www.baidu.com";
            //设定通知打开的activity，仅当AndroidOpenType="Activity"有效
            //request.AndroidActivity = "com.alibaba.push2.demo.XiaoMiPushActivity";
            //Android通知音乐
            AndroidMusic = "default",
            //设置该参数后启动小米托管弹窗功能，此处指定通知点击后跳转的Activity（托管弹窗的前提条件：1. 继承小米辅助通道；2. storeOffline设为true)
            AndroidXiaoMiActivity = "com.ali.demo.MiActivity",
            //小米弹窗标题
            AndroidXiaoMiNotifyTitle = pushData.Title,
            //小米弹窗内容
            AndroidXiaoMiNotifyBody = pushData.Body
        };
        // 设定android类型设备通知的扩展属性
        //request.AndroidExtParameters = "{\"k1\":\"android\",\"k2\":\"v2\"}";

        // 推送控制
        string pushTime = DateTime.UtcNow.AddSeconds(3).ToString("yyyy-MM-ddTHH\\:mm\\:ssZ");
        request.PushTime = pushTime;//延迟3秒发送
        string expireTime = DateTime.UtcNow.AddDays(2).ToString("yyyy-MM-ddTHH\\:mm\\:ssZ");
        request.ExpireTime = expireTime;//设置过期时间为2天
        request.StoreOffline = false;

        client.GetAcsResponse(request);
        return Task.CompletedTask;
    }

    #endregion

}
